package wcg;

import ikelib.unsigned_byte;
import ikelib.winfilename;
import ikelib.winindex;
import ikelib.wintime;
import ikelib.wintools;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 
 */

/**
 * @author ikechan
 *
 */
public class winchk implements Runnable {

	public String[] Argument = null;
	public int DisplayLevel = 2;
	public boolean InterCheck = true;
	public boolean Stop = false;
	public boolean Busy = false;
	public int Result=0;

	private int display;
	private wintime timecur= new wintime();
	private int   timecurMs = 0;

	private winindex curwindex;
	private ArrayList<winindex> IndexList = new ArrayList<winindex>();
	
	private int displaylevel;
	private ArrayList<winindex>[] chDataList; 
	private ArrayList<winindex> dataList;
	private ArrayList<Integer> chList ;
	public static final int WIN_FORMAT_A0 = 0;
	public static final int WIN_FORMAT_A5 = 5;
	public static final int TXT_FORMAT_KNET = 100;
	public static final int K_NET_CNTFILE = 200;
	public static final int WIN_FORMAT_A89 = 89;
	
	private int winFormat = WIN_FORMAT_A0; // 0: A0 5:A5
	public boolean noMessage = false; 
	// チェックしてOKの場合、winA0 か　winA5だったかを返す。
	public int getWinFormat(){
		return winFormat;
	}
	private void errorPrintln(String mes){
		if(!noMessage){
			System.err.println(mes);
		}
	}
	private void errorFormat(String fmt,Object... obj){
		if(!noMessage){
			System.err.format(fmt,obj);
		}
	}
	private void outPrintln(String mes){
		if(!noMessage){
			System.out.println(mes);
		}
	}
	private void outFormat(String fmt,Object... obj){
		if(!noMessage){
			System.out.format(fmt,obj);
		}
	}
	
	winchk()
	{
		displaylevel=0;
	}
	private void showusage(){
		outPrintln("*** Usage: winchk [-v(0..3)] winfile;winfile ... [/n] ");
		outPrintln("***  -v : message display level from -v0 (silent) to -v3 show all  ");
		outPrintln("***  -i : don't check the time continuum of inter files ");
		outPrintln("***  /n : specify winfile is generated automaticaly  n=1,2,3...");
		outPrintln("***  exsample .. winchk -v3 10071618.59 /10");
		
	}
	public int check(String[] args){
		outPrintln("*** WIN file check & dump   2010/2011/2012/2013/2014 ikeda@hakusan.co.jp ");
		if(args.length <= 0){
			showusage();
			System.exit(0);
		}
		int dsp=0;
		boolean InterCheck=true;
		//int  basename=-1;
		String fBaseName = new String("");
		ArrayList<String> a = new ArrayList<String>();
		// parse arguments
		for(int i=0;i<args.length;i++){
			//if(args[i].isEmpty()){
			if(args[i] == null){
				continue;
			}
			String ar = new String(args[i].toUpperCase());
			if(ar.getBytes()[0]=='-'){
				if(0==ar.compareTo("-V1")){
					dsp = 1;
				}
				else if(0==ar.compareTo("-V2")){
					dsp = 2;
				}
				else if(0==ar.compareTo("-V3")){
					dsp = 3;
				}
				else if(0==ar.compareTo("-I")){
					InterCheck = false;
				}
			}
			else if(ar.getBytes()[0]=='/'){
				if(!fBaseName.isEmpty()){ // check that a filename has specified before 
					String num = new String(ar.substring(1));	// get the number
					int rep = Integer.parseInt(num);
					winfilename name= new winfilename(fBaseName);
					while((rep--)>0){
						name.nameInc();
						a.add(name.name());
					}
				}
				//a.get(a.lastIndexOf(o));
			}
			else{	// this argument is filename to be checked
				String file  = new String(args[i]);
				String[] f = file.split(";");	// example file1;file2;file3 
				//  sort for time continuam 
				for(int k=f.length-1;k>0;k--){
					for(int j=0;j<k;j++){
						if(f[j].compareToIgnoreCase(f[j+1]) > 0){
							String tmp = f[j];
							f[j]=f[j+1];
							f[j+1]=tmp;
						}
					}
				}
				// add string list
				for(int j=0;j<f.length;j++){
					a.add(f[j]);
					fBaseName = f[j];
				}
			}
		}
		if(!fBaseName.isEmpty()){
			String[] b = a.toArray(new String[0]);
			return check(b,dsp,InterCheck);
		}
		else{
			showusage();
		}
		return 0;
	}

	private int check(String[] args,int dsp,boolean interchk){
		displaylevel = dsp;
		// ファイル１つずつ解析
		//if(displaylevel > 0){
			outPrintln("*** Start individual file checking ...");
		//}
		int err = 0;
		dataList  = new ArrayList<winindex>();
		for(int i=0;i<args.length;i++){
			//String ar = args[i].toUpperCase();
			// すべてのファイルの情報をまとめる。
			if(Stop){
				outPrintln("Aborted ");
				return -10;
			}
			//windump wd = new windump();
			//if(0!= wd.check(args[i],displaylevel)){
			if(0!=check(args[i],displaylevel,interchk)){
				err++;
				return -11;
			}
			//dataList.addAll(wd.IndexList);
			dataList.addAll(IndexList);
		}
		
		if (err == 0 && interchk) {
			//if(displaylevel > 0){
				outPrintln("*** Start all file data checking ...");
			//}
			// index listを表示
			//if(displaylevel > 2){
			//	outPrintln(" WIN files indexes ... \nDate Time file channel (encode rate) fileoffsetbyte");
			//}
			// ch listを作成
			int chnum = makeChList();
			if(chnum<0) return -11;
			outFormat("*** found %d channel \n" , chnum);
			// ch list をソート
			//  
			// ch data listを作成
			outPrintln("*** checking headers ...");
			makeChDataList();
			// ch data listの時刻をチェック
			if(0!=checkTimeOfChDataList()){
				err++;
				return -11;
			}
		}
		if (0 == err) {
			outPrintln("--------------------------------\n*** No error found\n\n");
		} else {
			outFormat("--------------------------------\n %d or more error found \n\n", err);
			errorFormat("--------------------------------\n %d or more error found \n\n", err);
		}
		return err;
	}
	/**
	 * 
	 */
	private int checkTimeOfChDataList() {
		// ｃｈ毎に時刻をチェック
		int error=0;
		for(int i=0;i<chList.size();i++){
			if(Stop){
				outPrintln("Aborted");
				return -10;
			}
			if(displaylevel > 1){
				//outFormat(" checking %x ... \n",chList.get(i));
				outFormat(" checking %s ... \n",winindex.getChannelName(chList.get(i)));
			}
			ArrayList<winindex> ar = chDataList[i];
			
			if(displaylevel > 1){
				winindex widx = ar.get(0);
				String encStr = "";
				switch(widx.enc){
				case 0: encStr = "0.5"; break;
				case 1: encStr = "1"; break;
				case 2: encStr = "2"; break;
				case 3: encStr = "3"; break;
				case 4: encStr = "4"; break;
				}
				int sr  = widx.rate;
				if(winFormat ==WIN_FORMAT_A5 ) sr *= 10;
				outFormat("  win format=A%d sample rate=%d , code size=%sbyte \n", winFormat,sr,encStr);
			}
			Iterator<winindex> ite = ar.iterator();
			int err=0;
			boolean first = true;
			winindex w1 = new winindex();
			winindex w  = new winindex();
			wintime timestart = new wintime();
			wintime timeend = new wintime();
			while(ite.hasNext()){
				winindex w0 = ite.next();
				//outFormat("--%s\n", w0.time.fmt());
				if(displaylevel>2){ 
					if(DisplevelTrancCounter4>0){
						DisplevelTrancCounter4--;
						outFormat("  %s\n", w0.time.fmt());
					}
					else if(DisplevelTrancCounter4==0){
						DisplevelTrancCounter4--;
						outPrintln("...\n.(abbreviated).\n...");
					}
				}
				if(first){
					timestart = w0.time;
				}
				else{
					w = new winindex(w1);
					if(winFormat==WIN_FORMAT_A0){
						w.time.inc_sec();
						timeend = w0.time;
						if(0 != w.time.compare(w0.time)){
							errorFormat(" error time continuum \n   %s\n<->%s\n",w0.fmt(),w.fmt());
							err++;
						}
					}
					else if(winFormat==WIN_FORMAT_A5){
						int ms = w.time.msec();
						ms += 100;
						if(ms >= 1000){
							ms = 0;
							w.time.inc_sec();
						}
						w.time.setMSec(ms);
						timeend = w0.time;
						if(0 != w.time.compare(w0.time)){
							errorFormat(" error time continuum \n   %s\n<->%s\n",w0.fmt(),w.fmt());
							err++;
						}
					}
				}
				first = false;
				w1 = new winindex(w0);
				if(err>10){
					errorPrintln("Too many error");
					return -100;
				}
			}
			if(err==0){
				if(displaylevel > 1){
					outFormat(" correct (%s -> %s)\n",timestart.fmt(),timeend.fmt());
				}
			}
			error += err;
		}
		return error;
	}
	/**
	 * Make channel data list 
	 * @return
	 */
	private int makeChDataList() {
		// ｃｈ毎にLISTを作成
		int num = chList.size();
		chDataList = new ArrayList[num];
		for(int i=0;i<num;i++){
			chDataList[i] = new ArrayList<winindex>();
		}
		int i=0;
		Iterator<Integer> ite2 = chList.iterator();
		while(ite2.hasNext()){
			if(Stop){
				outPrintln("Aborted ");
				return -10;
			}
			int chno = ite2.next();
			Iterator<winindex> ite3 = dataList.iterator();
			while(ite3.hasNext()){
				winindex w = ite3.next();
				if(w.ch == chno){
					chDataList[i].add(new winindex(w));
					if(displaylevel > 2){
						//outPrintln(w.fmt());
					}
				}
			}
			i++;
		}
		return i;
	}
	
	private int makeChList() {
		// ｃｈのLIｓｔを作成
		chList = new ArrayList<Integer>();
		Iterator<winindex> ite = dataList.iterator();
		while(ite.hasNext()){
			if(Stop){
				outPrintln("Aborted ");
				return -1;
			}
			winindex w = ite.next();
			Iterator<Integer> i = chList.iterator();
			boolean find=false;
			while(i.hasNext()){
				int chno = i.next();
				if(chno == w.ch){
					find = true;
					break;
				}
			}
			if(!find){
				chList.add(w.ch);
				if(displaylevel > 1){
					//	outFormat("  found channel %x\n" ,w.ch);
					outFormat("  found channel %s\n" ,winindex.getChannelName(w.ch));
				}
			}
		}
		return chList.size();
	}
	/**
	 * @param args
	 */
//	public static void main(String[] args) {
//		
//		winchk wchk = new winchk();
//		try{
//			wchk.check(args);
//		}
//		catch(Exception e){
//			System.err.print(e.getMessage());
//		}
//	}
//
	@Override
	public void run() {
		Busy=true;
		//Result = check(Argument);
		winchk chk = new winchk();
		Result =  chk.check(Argument);
		Busy=false;
	}
	// -------------------------------------------------------------
	private String File = new String();	// for report
	private int CurOffsetByte;		// Offset byte for report
	private int CurSecBlocks;	// Second blocks for report
	private int CurChBlocks;	// channel blocks for report
	private int CurChNo;		// channel number for report
	private int DisplevelTrancCounter1=16;
	private int DisplevelTrancCounter2=16;
	private int DisplevelTrancCounter3=16;
	private int DisplevelTrancCounter4=16;
	/*
	 * Nothing to be done  
	 */
	/**
	 * Truncate the file name for display. example "c:/user/documents/data/20100821.59" -> "c:/user...ata/20100821.59"
	 * @param longname 	 
	 * File name to be truncated 
	 * @param maxlength
	 * Maximum length of truncated file name
	 * @param minfilenamelength
	 * Minimum length of filename that is part of end of longname 
	 * @return
	 * Truncated String
	 */
	private String getTruncateFilename(String longname,int maxlength,int minfilenamelength){
		String ret = new String();
		if(longname.length() > maxlength){
			ret = longname.substring(0, maxlength-3-minfilenamelength);
			ret += "...";
			ret += longname.substring(longname.length()-minfilenamelength,longname.length());
		}
		else{
			ret = longname;
		}
		return ret;
	}
	private String getCommonInfo(){
		String ret = new String();
		String filename = getTruncateFilename(File,30,20);
		//ret = String.format(" [%s offset=%d SecondBlock=%d ChannelBlock=%d Channel=%04xH]", filename,CurOffsetByte,CurSecBlocks,CurChBlocks,CurChNo);
		ret = String.format(" [%s offset=%d SecondBlock=%d ChannelBlock=%d Channel=%s]", filename,CurOffsetByte,CurSecBlocks,CurChBlocks,winindex.getChannelName(CurChNo));
		return ret;
	}
	/**
	 * 
	 * @param c  パケット長以下のwinA0/A5データ
	 * @param filelength　// データ長
	 * @return　0=WIN_FORMAT_A0 . 5=WIN_FORMAT_A5 . 100=TXT_FORMAT_KNET . 200=K_NET_CNTFILE . -1=Unknown
	 */
	public static int getFileFormat(byte[] c,int filelength){
		
		if(c.length<10) return -1;
		if((char)(c[0])=='O' && (char)(c[1])=='r' && (char)(c[2])=='i' && (char)(c[3])=='g' && (char)(c[4])=='i' && (char)(c[5])=='n' ){
			return TXT_FORMAT_KNET;
		}
		if(c[0]==-125 && c[1]==6){	// 	固有のID 0x8306xxxxx ファイル長より長い（多分）
			return K_NET_CNTFILE;
		}
		
		int index = 0;
		long pacsize = unsigned_byte.convShort(c[index])*0x1000000L 
					+ unsigned_byte.convShort(c[index+1])*0x10000L  
					+ unsigned_byte.convShort(c[index+2])*0x100L 
					+ unsigned_byte.convShort(c[index+3]);
		if(filelength < pacsize){
			return -1;
		}
		if(c.length < pacsize){
			return -1;
		}
		index += 4;
		if(filelength == pacsize){ // 1秒分しかないパケット
			int idx = 6;
			int bsize = 0;
			boolean err = false;
			while(index+idx<pacsize){
				int bs = wintools.getChannelBlockSize(c, index+idx);
				if(bs<=0){
					err = true;
					break;
				}
				idx += bs;
			}
			if(index+idx == pacsize){
				return WIN_FORMAT_A0;
			}
			idx = 7;
			bsize = 0;
			err = false;
			while(index+idx<pacsize){
				int bs = wintools.getChannelBlockSize(c, index+idx);
				if(bs<=0){
					err = true;
					break;
				}
				idx += bs;
			}
			if(index+idx+1 == pacsize){
				return WIN_FORMAT_A5;
			}
			return WIN_FORMAT_A89;// WIN A8,A9等を想定(エラーフォーマットかもしれないが）→無視する
		}
		
		if(c[index] == c[index+(int)pacsize] 
		     && c[index+1] == c[index+(int)pacsize+1] 
		     && c[index+2] == c[index+(int)pacsize+2]
		     && c[index+3] == c[index+(int)pacsize+3]
		     && c[index+4] == c[index+(int)pacsize+4]
		     && c[index+5] == c[index+(int)pacsize+5]){
			return WIN_FORMAT_A5;
		}
		return WIN_FORMAT_A0;
	}
	/**
	 * Check the WIN file 
	 * @param file
	 * a WIN file name
	 * @param disp
	 * displaylevel 0..3
	 * @return
	 * error count. 0=no error
	 */
	public int check(String file,int disp,boolean chktimecontinum){
		int filelength ;
		display = disp;
		byte[] c;
		File = file;
		String mes = new String();
		
		IndexList.clear();
		
		try{
			if(display>0){
				outPrintln(" Start checking format " + file);
			}
			FileInputStream in = new FileInputStream(file);
			filelength = in.available();
			c = new byte[filelength];
			in.read(c,0,filelength);
			in.close();
			if(display>0){
				mes = String.format(" %dbyte", filelength);
				outPrintln(mes);
			}
			
		}
		catch(Exception e){
			throw new RuntimeException(e);
		}
		curwindex = new winindex();
		curwindex.file = file;
	
		// A0,A5,TXT_KNETどちらか？
		winFormat = getFileFormat(c,filelength);
		
		
		if(winFormat < -1){
			winFormat = 0;
		}
		noMessage=false;
		int ret = -1;
		switch(winFormat){
		case WIN_FORMAT_A0: 
			if(display>0){
				outPrintln(" Checking as WIN A0  ...");
			}
			ret = checkBlocks(c,filelength,chktimecontinum);
			break;
		case WIN_FORMAT_A5: 
			if(display>0){
				outPrintln(" Checking as WIN A5  ...");
			}
			ret = checkBlocks(c,filelength,chktimecontinum);
			break;
		case TXT_FORMAT_KNET: 
			if(display>0){
				outPrintln(" Checking as K-NET Ascii  ...");
			}
			ret = checkTextFormat(file,TXT_FORMAT_KNET);
			break;
		case K_NET_CNTFILE: 
			if(display>0){
				outPrintln(" Checking as K-NET CNT  ...");
			}
			ret = checkBinaryFormat(file,K_NET_CNTFILE,disp);
			break;
		default:
			if(display>0){
				outPrintln(" Unknown format  ...");
				outPrintln(getHexDump(c,0,16,0));
			}
			break;
		}
		
		if(ret == 0){
			if(display>0){
				outPrintln(" Correct");
			}
		}
		else {
			if(display>0){
				outPrintln(" Error");
			}
			return -1;
		}
		return 0;
		
	}
	/**
	 * テキスト形式のフォーマットをチェックする
	 * @param file
	 * @param type
	 * @return
	 * 0=正常、
	 */
	private int checkTextFormat(String file,int type){
		if(type == TXT_FORMAT_KNET){
			// 実際に読み込んでみる
			KNET_ascii knet = new KNET_ascii(file);
			if(knet.Data==null){
				outPrintln(" K-NET asccii format error ");
				return -1;
			}
			return 0;
		}
		return -1;// unknown format
	}
	/**
	 * バイナリ形式のフォーマットをチェックする
	 * @param file
	 * @param type
	 * @return
	 * 0=正常、
	 */
	private int checkBinaryFormat(String file,int type,int displalevel){
		if(type == K_NET_CNTFILE){
			// 実際に読み込んでみる
			K_NET_CNT cnt = new K_NET_CNT(file);
			if(cnt.DataRow!=null){
				cnt.DisplayLevel=displaylevel;
				if(0!=cnt.check()){
					outPrintln(" K-NET cnt format error ");
					return -1;
				}
			}
			return 0;
		}
		return -1;// unknown format
	}
	/**
	 * バイナリブロックをチェック
	 * @param c
	 * バイナリデータ
	 * @param size
	 * チェックするべきサイズ
	 * @param baseoffset
	 * スタートするインデックス
	 * @return
	 * 0=正常、　<0 = 鰓0
	 */
	private int checkChBlocks(byte[] c, int size , int baseoffset){
		int index=0;
		int smpl;
		int rate;
		int expectbyte;
		CurChBlocks=0;
		String mes = new String();
		while(index < size){
			if(Stop){
				outPrintln("Aborted ");
				return -10;
			}
			if((index+4) >= size){
				mes = String.format(" A%d No space for channel header ",winFormat);
				errorPrintln(mes+getCommonInfo());
				return -1;
			}
			CurChNo = unsigned_byte.convShort(c[index])*0x100 + unsigned_byte.convShort(c[index+1]);
			index += 2;
			CurOffsetByte += 2;
			smpl = (0xf0 & (unsigned_byte.convShort(c[index])))>>4;
			if(smpl>4 || smpl < 0){
				mes = String.format(" A%d Irregal encode=%d ",winFormat,smpl);
				errorPrintln(mes+getCommonInfo());
				errorPrintln(" channel header:"+getHexDump(c,index-2,4,CurOffsetByte-2));
				return -2;
			}
			rate = 0xfff & (unsigned_byte.convShort(c[index])*0x100 + unsigned_byte.convShort(c[index+1]));
			if(rate<=0){
				mes = String.format(" A%d Irregal rate=%d ",winFormat,rate);
				errorPrintln(mes+getCommonInfo());
				errorPrintln(" channel header:"+getHexDump(c,index-2,4,CurOffsetByte-2));
				return -1;
			}
			index += 2;
			CurOffsetByte += 2;
			if(smpl == 0){	// 0.5byte 
				expectbyte = 4 + rate / 2;
			}
			else{	// 1byte,2byte,3byte,4byte
				expectbyte = 4 + ((rate-1) * smpl);
			}
			//baseoffset += index;
			curwindex.dataoffset = baseoffset + index;
			curwindex.ch = CurChNo;
			curwindex.enc = smpl;
			curwindex.rate = rate;
			winindex wi = new winindex(curwindex);
			IndexList.add(wi);
			if(display > 2){
				if(DisplevelTrancCounter1>0){
					DisplevelTrancCounter1--;
					//mes = String.format("   ch=%04xH encode=%d rate=%d secblock=%d (chblock=%d)",CurChNo,smpl,rate,CurSecBlocks,CurChBlocks); 
					mes = String.format("   A%d ch=%s encode=%d rate=%d secblock=%d (chblock=%d)",winFormat,winindex.getChannelName(CurChNo),smpl,rate,CurSecBlocks,CurChBlocks); 
					outPrintln(mes);
				}
				else if(DisplevelTrancCounter1==0){
					DisplevelTrancCounter1--;
					outPrintln("...\n.(abbreviated).\n...");
				}
			}
			//String mes = String.format(" : %x,%d,%d",chnum,smpl,rate); System.out.print(mes);
			index += expectbyte;
			CurChBlocks++;
			// debug System.out.format("A%d : index=%d, expectedbyte=%d , chblock=%d\n", winFormat,index,expectbyte,CurChBlocks);
		}
		//System.out.print("\n");
		if(index != size){
			mes = String.format(" A%d Irregal channel block size=%d/%d",winFormat,index,size);
			errorPrintln(mes+getCommonInfo());
			return -3;
		}
		return 0;
	}
	/**
	 * 秒ブロックをチェック
	 * @param c  
	 * data 
	 * @param size
	 * the value of size 
	 * @param baseoffset
	 * 
	 * @return
	 * 0=正常　<0 = エラー
	 */
	private int checkSecBlock(byte[] c, int size, int baseoffset)
	{
		// check the second block header
		String mes = new String();
		if(size <= (4+6)){
			mes = String.format(" A%d Second block size(=%d) is too small",winFormat, size);
			errorPrintln(mes+getCommonInfo());
			return -2;
		}
		int index = 4;
		byte[] bcd = new byte[6];
		for(int i=0;i<bcd.length;i++){
			bcd[i] = c[index+i];
		}
		wintime tm = new wintime(bcd);

		if(winFormat == 0){
			index += 6;
		}
		else{
			byte tmp = c[index+6];
			timecurMs = (tmp & 0xf)*10 + ((tmp>>4) & 0xf)*100; 
			tm.setMSec(timecurMs);
			index += 7; // winA5
		}

		timecur = tm;
		curwindex.time = tm; 
		
		CurOffsetByte += index;
		
		if(display > 2){
			if(DisplevelTrancCounter2>0){
				DisplevelTrancCounter2--;
				mes = String.format(" "+tm.fmt()); 
				// String mes2 = String.format(" sec block size=%d", size - index);
				outPrintln("  time=" + mes);
			}
			else if(DisplevelTrancCounter2==0){
				DisplevelTrancCounter2--;
				outPrintln("...\n.(abbreviated).\n...");
			}
		}
		byte[] b = new byte[size - index];
		for(int i=0;i<b.length;i++){
			b[i] = c[i+index];			
		}
		return checkChBlocks(b,size-index, baseoffset+index);
	}
	/**
	 * Make a string of hex dump 
	 * @param c
	 * @param start
	 * はじめ
	 * @param length
	 * 長さ
	 * @param dispadr
	 * 表示されるアドレス
	 * @return
	 * 文字列
	 */
	private String getHexDump(byte[] c,int start,int length,int dispadr){
		String ret = new String();
		ret = String.format("%06x:",dispadr);
		for(int i=start;i<start+length;i++){
			int dat = c[i];
			if(dat <0) dat = 0x100 - dat;
			ret += String.format("%02x", dat);
			if((i % 4)==0 && i!=0){
				ret += "-";
			}
			else{
				ret += " ";
			}
		}
		return ret;
	}
	/**
	 * ブロックをチェックする
	 * @param c
	 * データ
	 * @param size
	 * 長さ
	 * @param chktimecontinum
	 * 時刻の連続性をチェックするか
	 * @return
	 * 0=OK　0> 何かエラー
	 */
	private int checkBlocks(byte[] c,int size,boolean chktimecontinum){
		int index = 0;
		CurOffsetByte = 0;
		CurSecBlocks = 0;
		boolean first = true;
		wintime timeold = new wintime();
		int     timemsold=0;
		String mes = new String();
		while(index < size){
			if(Stop){
				outPrintln("Aborted");
				return -10;
			}
			int bsize = unsigned_byte.convShort(c[index])*0x1000000 
				+ unsigned_byte.convShort(c[index+1])*0x10000 
				+ unsigned_byte.convShort(c[index+2])*0x100 
				+ unsigned_byte.convShort(c[index+3]);	
			if(bsize<=10){
				String mes2 = String.format(" WIN-A%d Sec block size(=%d) is too small.\n It should be more than 10 ",winFormat, bsize);
				errorPrintln(mes2);
				errorPrintln(" block header:"+getHexDump(c,0,10,CurOffsetByte));
			}
			if(bsize+index > size){
				String mes2 = String.format(" WIN-A%d Sec block size(=%d) is too big.\n It should be less or equal remain(=%d) ", winFormat,bsize,size-index);
				errorPrintln(mes2);
				errorPrintln(" block header:"+getHexDump(c,0,10,CurOffsetByte));
				return -11;
			}
			if(display > 2){
				if(DisplevelTrancCounter3>0){
					DisplevelTrancCounter3--;
					String mes2 = String.format(" A%d sec block=%d lenght=%d", winFormat, CurSecBlocks,bsize); 
					outPrintln(mes2);
				}
				else if(DisplevelTrancCounter3==0){
					DisplevelTrancCounter3--;
					outPrintln("...\n.(abbreviated).\n...");
				}
			}
			byte[] s = new byte[(int)bsize];
			for(int i=0;i<s.length;i++){
				s[i] = c[index+i];
			}
			// check the second block
			int ret =checkSecBlock(s,bsize,index);
			if(ret != 0){
				return ret; // error
			}
			// check the time continuum
			if(chktimecontinum){
				if(winFormat == WIN_FORMAT_A0){
					if(first){
						timeold  = new wintime(timecur);
						first = false;
					}
					else{
						timeold.inc_sec();
						if(0!=timeold.compare(timecur)){
							errorPrintln(" A0 Error in time continuum  " + timeold.fmt() + "<->" + timecur.fmt()  +getCommonInfo());
							return -3;
						}
						timeold = new wintime(timecur);
					}
				}
				else if(winFormat == WIN_FORMAT_A5){
					if(first){
						timeold  = new wintime(timecur);
						timemsold = timecurMs;
						first = false;
					}
					else{
						timemsold += 100;
						if(timemsold>=1000){
							timeold.inc_sec();
							timemsold=0;
						}
						if(0!=timeold.compare(timecur) || timemsold!=timecurMs){
							errorPrintln(" A5 Error in time continuum " + timeold.fmt() + "." + timemsold + "<->" + timecur.fmt()+"."+ timecurMs  +getCommonInfo());
							return -3;
						}
						timeold = new wintime(timecur);
					}
				}
			}
			index += (bsize);
			CurOffsetByte += (bsize);
			CurSecBlocks++;
		}
		if(index != size){
			mes = String.format(" A%d Irregal block size %d/%d",winFormat,index,size);
			errorPrintln(mes+getCommonInfo());
			return -2;		// not correct size
		}
		return 0; // correct;
	}
	


	// -------------------------------------------------------------
	
}
